package ru.urfc.portal.ui.client.widgets;

import java.util.ArrayList;
import java.util.List;

import ru.urfc.portal.ui.client.Agregator;
import ru.urfc.portal.ui.client.AgregatorListener;
import ru.urfc.portal.ui.client.BaseDocument;
import ru.urfc.portal.ui.client.Constants;
import ru.urfc.portal.ui.client.Utils;
import ru.urfc.portal.ui.client.controllers.ItemsController;
import ru.urfc.portal.ui.client.controllers.SimpleItemsController;
import ru.urfc.portal.ui.client.descriptor.GridDescriptor;
import ru.urfc.portal.ui.client.descriptor.GridField;

import com.extjs.gxt.ui.client.data.LoadEvent;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.LoadListener;
import com.extjs.gxt.ui.client.event.Observable;
import com.extjs.gxt.ui.client.widget.form.FileUploadField;
import com.extjs.gxt.ui.client.widget.form.FormPanel;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Widget;

/**
 * TODO testing and refactoring
 */
public class AttachedFiles extends Composite implements Constants {

	interface Binder extends UiBinder<Widget, AttachedFiles> {}
	private static Binder binder = GWT.create(Binder.class);

	private int filesToDownloadCount = 0; 
	private List<String> filesToDelete = new ArrayList<String>();
	private int filesToUploadCount = 0;
	
	@UiField AttachedFilesPanel files;
	@UiField Anchor createNew;
	@UiField FormPanelWrapper formPanelWrapper;
	FormPanel formPanel; 
	
	ItemsController downloadableFilesController;

	public AttachedFiles() {
		initWidget(binder.createAndBindUi(this));
		formPanel = formPanelWrapper.getFormPanel();
	}
	
	public void init(final BaseDocument document) {
		formPanel.setAction(Utils.createRestUrl(CLIENTS, document.getClientId(), DOCUMENTS, document.getItemId(), DOCUMENT_ATTACHED_FILES));
		formPanel.setMethod(FormPanel.Method.POST);
		formPanel.setEncoding(FormPanel.Encoding.MULTIPART);
		Utils.hide(createNew.getElement());
		
		document.getController().getLoader().addLoadListener(new LoadListener() {
			@Override
			public void loaderLoad(LoadEvent le) {
				onDocumentLoaded(document);				
			}	
		});
		document.getController().addListener(ItemsController.BEFORE_PUT_EVENT, new Listener<BaseEvent>() {
			@Override
			public void handleEvent(BaseEvent be) {
				deleteAndUploadFiles(document);
			}
		});
		createNew.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				createUploadItem();
			}
		});
		createDownloadableFilesController(document);
	}
	
	private void onDocumentLoaded(final BaseDocument document) {
		if (document.isDraft()) {
			Utils.show(createNew.getElement());
			updateCreateNewText();
		} else {
			Utils.hide(createNew.getElement());
		}
		downloadableFilesController.doGet();
	}
	
	private void createDownloadableFilesController(final BaseDocument document) {
		GridDescriptor descriptor = new GridDescriptor(ATTACHED_FILE, CLIENTS, document.getClientId(), DOCUMENTS, document.getItemId(), DOCUMENT_ATTACHED_FILES);
		final GridField nameField = descriptor.addField("name");
		downloadableFilesController = new ItemsController(descriptor) {
			@Override
			protected void onUpdate(List<ModelData> data) {
				files.clear();
				boolean isDraft = document.isDraft();
				for (ModelData modelData: data) {
					String fileName = nameField.getValue(modelData);
					createDownloadableItem(descriptor.getRestUrl(), fileName, isDraft);
				}
				filesToDownloadCount = data.size();
				if (filesToDownloadCount == 0 && isDraft) {
					createUploadItem();
				}
				updateCreateNewText();
			}
		};		
	}
	
	private void createDownloadableItem(String restUrl, final String fileName, boolean isDraft) {
		Anchor download = new Anchor(fileName, restUrl + "/" + fileName);
		if (isDraft) {
			Anchor delete = new Anchor("удалить");
			final Element row = files.addRow(download, createHSpacer(), delete);
			delete.addClickHandler(new ClickHandler() {
				@Override
				public void onClick(ClickEvent event) {
					filesToDelete.add(fileName);
					updateCreateNewText();
					row.removeFromParent();
				}
			});
		} else {
			files.addRow(download);
		}
	}
	
	private void createUploadItem() {
		final FileUploadField upload = new FileUploadField();
		upload.setWidth("250");
		upload.setName("upload");
		Anchor delete = new Anchor("удалить");
		final Element row = files.addRow(upload, createHSpacer(), delete);
		delete.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				--filesToUploadCount;
				updateCreateNewText();
				row.removeFromParent();
			}
		});
		++filesToUploadCount;
		updateCreateNewText();
	}
	
	private HTML createHSpacer() {
		return new HTML("<span class='h-spacer'/>");
	}
	
	private void updateCreateNewText() {
		createNew.setText((filesToDownloadCount + filesToUploadCount - filesToDelete.size() > 0) ?
				"Приложить дополнительные файлы" : "Приложить файл");		
	}

	private SimpleItemsController createDeleteFileController(BaseDocument document, String fileName) {
		GridDescriptor descriptor = new GridDescriptor("", CLIENTS, document.getClientId(), DOCUMENTS, document.getItemId(), DOCUMENT_ATTACHED_FILES, fileName);
		return new SimpleItemsController(descriptor) {						
			@Override
			public void onUpdate(Object data) {
			}
		};
	}

	private void deleteAndUploadFiles(final BaseDocument document) {
		Agregator agregator = new Agregator();
		List<SimpleItemsController> deleteControllers = new ArrayList<SimpleItemsController>();
		for (String fileName: filesToDelete) {
			SimpleItemsController controller = createDeleteFileController(document, fileName); 
			agregator.listenLoaded(controller.getSimpleLoader());
			deleteControllers.add(controller);
		}
		agregator.addListener(Agregator.AGREGATED, new AgregatorListener() {
			@Override
			public void agregated() {
				filesToDelete.clear();
			}
		});
		uploadFiles(agregator);
		for (SimpleItemsController controller: deleteControllers) {
			controller.doDelete();
		}
		agregator.check();
	}
	
	private void uploadFiles(Observable observable) {
		if (filesToUploadCount == 0) {
			return;
		}
		Agregator agregator = new Agregator();
		agregator.listen(observable, Agregator.AGREGATED);
		agregator.addListener(Agregator.AGREGATED, new AgregatorListener() {
			@Override
			public void agregated() { // All files deleted
				Agregator agregator = new Agregator();
				agregator.listen(formPanel, Events.Submit);
				agregator.addListener(Agregator.AGREGATED, new AgregatorListener() {
					@Override
					public void agregated() {
						downloadableFilesController.doGet();
					}
				});
				filesToUploadCount = 0;
				formPanel.submit();
			}
		});
		
	}
	
}
